using System;
using NUnit.Framework;
using ValidationFramework.Reflection;

namespace ValidationFramework.Tests
{

	[TestFixture]
	public class EnumConversionRuleTest
	{
		public enum Numbers
		{
			One = 1,
			Two = 2,
			Three = 3
		}
		public enum Letters
		{
			A,
			B,
			C
		}
		const string expectedErrorMessage = "expectedErrorMessage";
		const string expectedRuleSet = "EXPECTEDRULESET";
		private static readonly Type numbersEnumType = typeof(Numbers);
		private static readonly Type lettersEnumType = typeof(Letters);

		[TestFixture]
		public class Contruction
		{
			[Test]
			public void AllParams()
			{
				var rule = new EnumConversionRule(expectedErrorMessage, false, typeof(Numbers),true);
				Assert.AreEqual(numbersEnumType, rule.EnumType);
				Assert.AreEqual(expectedErrorMessage, rule.ErrorMessage);
				Assert.IsFalse(rule.UseErrorMessageProvider);
			}
			[Test]
			public void NoParams()
			{
				var rule = new EnumConversionRule(typeof(Numbers));
				Assert.AreEqual(numbersEnumType, rule.EnumType);
				Assert.AreEqual(null, rule.ErrorMessage);
				Assert.IsFalse(rule.UseErrorMessageProvider);
			}
			[Test]
			public void ErrorMessageParams()
			{
				var rule = new EnumConversionRule(expectedErrorMessage, typeof(Numbers));
				Assert.AreEqual(numbersEnumType, rule.EnumType);
				Assert.AreEqual(expectedErrorMessage, rule.ErrorMessage);
				Assert.IsFalse(rule.UseErrorMessageProvider);
			}

		}

		[TestFixture]
		public class IsEquivalent
		{

			[Test]
			public void TypeCompare()
			{
				var rule1 = new EnumConversionRule(null, false, numbersEnumType, true);
				var rule2 = new EnumConversionRule(null, false, numbersEnumType, true);
				Assert.IsTrue(rule1.IsEquivalent(rule2));

				rule1 = new EnumConversionRule(null, false, numbersEnumType, true);
				 rule2 = new EnumConversionRule(null, false, lettersEnumType, true);
				Assert.IsFalse(rule1.IsEquivalent(rule2));
			}
		}



		[TestFixture]
		public class RuleInterpretation
		{
			[Test]
			public void Simple()
			{
				var rule = new EnumConversionRule(null, false, numbersEnumType, true);
				Assert.IsNotNull(rule.RuleInterpretation);

			}
		}

		[TestFixture]
		public class Validate
		{

			[Test]
			public void String()
			{
			    var rule = new EnumConversionRule(null, false, numbersEnumType, true);
			    var infoDescriptor = new MockInfoDescriptor(TypePointers.StringTypeHandle, "foo");
			    rule.CheckType(infoDescriptor);

                Assert.IsNull(rule.Validate(null, null, null, infoDescriptor));
                Assert.IsNull(rule.Validate(null, string.Empty, null, infoDescriptor));
                Assert.IsNotNull(rule.Validate(null, "kjn", null, infoDescriptor));
                Assert.IsNull(rule.Validate(null, "One", null, infoDescriptor));
			}
			[Test]
			public void Int()
			{
			    var rule = new EnumConversionRule(null, false, numbersEnumType, true);
			    var infoDescriptor = new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo");
			    rule.CheckType(infoDescriptor);

                Assert.IsNull(rule.Validate(null, null, null, infoDescriptor));
                Assert.IsNull(rule.Validate(null, 1, null, infoDescriptor));
                Assert.IsNotNull(rule.Validate(null, 5, null, infoDescriptor));
                Assert.IsNotNull(rule.Validate(null, -4, null, infoDescriptor));
                Assert.IsNotNull(rule.Validate(null, 0, null, infoDescriptor));
			}

		}

		[TestFixture]
		public class CheckTypes
		{


            [Test]
            public void Simple()
            {
                var rule = new EnumConversionRule(null, false, numbersEnumType, true);
                rule.CheckType(new MockInfoDescriptor(TypePointers.StringTypeHandle, "foo"));
            }


            [Test]
            [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Member 'foo' must be a byte, short, int, long, ushort, ulong, uint or string to be used for the ValidationFramework.EnumConversionRule. Actual Type 'System.DateTime'.\r\nParameter name: value")]
            public void ExceptionIncorrectType()
            {
                var rule = new EnumConversionRule(null, false, typeof (Numbers), false);
                rule.CheckType(new MockInfoDescriptor(typeof (DateTime).TypeHandle, "foo"));
            }
		}

	}
}